package com.eedi.framework.template.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.eedi.framework.common.enums.CommonStatusEnum;
import com.eedi.framework.common.pojo.PageResult;
import com.eedi.framework.common.util.collection.CollectionUtils;
import com.eedi.framework.template.controller.sys.vo.menu.SysTemplateMenuSaveReq;
import com.eedi.framework.template.controller.sys.vo.permission.SysTemplateRoleMenuResp;
import com.eedi.framework.template.controller.sys.vo.role.SysTemplateRoleSaveReq;
import com.eedi.framework.template.controller.sys.vo.role.SysTemplateRoleUpReq;
import com.eedi.framework.template.convert.SysTemplateRoleMenuConvert;
import com.eedi.framework.template.dal.dataobject.SysTemplateRoleDO;
import com.eedi.framework.template.dal.mapper.SysTemplateRoleMenuMapper;
import com.eedi.framework.template.enums.SysTemplateDataScopeEnum;
import com.eedi.framework.template.controller.sys.vo.menu.SysTemplateMenuListReq;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.eedi.framework.template.dal.dataobject.SysTemplateRoleMenuDO;

import javax.annotation.Resource;
import java.util.*;

import com.eedi.framework.template.controller.sys.vo.role.SysTemplateRolePageReq;

import com.eedi.framework.template.dal.dataobject.SysTemplateMenuDO;

import static com.eedi.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.eedi.framework.common.util.collection.CollectionUtils.convertSet;
import static com.eedi.framework.template.enums.SysTemplatePermissionErrorCodeConstants.SYS_TEMPLATE_MENU_NOT_EXISTS;

/**
 * 权限 Service 实现类
 *
 * @author 永聚长青源码
 */
@Service
@Slf4j
public class SysTemplatePermissionServiceImpl implements SysTemplatePermissionService {

    @Resource
    private SysTemplateRoleMenuMapper sysTemplateRoleMenuMapper;


    @Resource
    private SysTemplateRoleService sysTemplateRoleService;
    @Resource
    private SysTemplateMenuService sysTemplateMenuService;


    // ========== 角色-菜单的相关方法  ==========

    @Override
    @DSTransactional // 多数据源，使用 @DSTransactional 保证本地事务，以及数据源的切换
    public void assignRoleMenu(String roleId, Set<String> menuIds) {
        // 检查新增菜单是否存在
        sysTemplateMenuService.validateMenuIds(menuIds);
        // 获得角色拥有菜单编号
        Set<String> dbMenuIds = convertSet(sysTemplateRoleMenuMapper.selectListByRoleId(roleId), SysTemplateRoleMenuDO::getSysMenuId);
        // 计算新增和删除的菜单编号
        Set<String> menuIdList = CollUtil.emptyIfNull(menuIds);
        Collection<String> createMenuIds = CollUtil.subtract(menuIdList, dbMenuIds);
        Collection<String> deleteMenuIds = CollUtil.subtract(dbMenuIds, menuIdList);
        // 执行新增和删除。对于已经授权的菜单，不用做任何处理
        if (CollUtil.isNotEmpty(createMenuIds)) {
            sysTemplateRoleMenuMapper.insertBatch(CollectionUtils.convertList(createMenuIds, menuId -> {
                SysTemplateRoleMenuDO entity = new SysTemplateRoleMenuDO();
                entity.setSysRoleId(roleId);
                entity.setSysMenuId(menuId);
                return entity;
            }));
        }
        if (CollUtil.isNotEmpty(deleteMenuIds)) {
            sysTemplateRoleMenuMapper.deleteListByRoleIdAndMenuIds(roleId, deleteMenuIds);
        }
    }

    @Override
    public void removeRoleMenu(String roleId, Set<String> menuIds) {
        // 检查新增菜单是否存在
        sysTemplateMenuService.validateMenuIds(menuIds);
        // 获得角色拥有菜单编号
        Set<String> dbMenuIds = convertSet(sysTemplateRoleMenuMapper.selectListByRoleId(roleId), SysTemplateRoleMenuDO::getSysMenuId);
        //检查是否有该菜单
        for (String menuId : dbMenuIds) {
            if (!dbMenuIds.contains(menuId)) {
                throw exception(SYS_TEMPLATE_MENU_NOT_EXISTS);
            }
        }
        sysTemplateRoleMenuMapper.deleteListByRoleIdAndMenuIds(roleId, menuIds);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void processRoleDeleted(String roleId) {
        // 标记删除 RoleMenu
        sysTemplateRoleMenuMapper.deleteListByRoleId(roleId);
    }

    @Override
    public void processMenuDeleted(String menuId) {
        sysTemplateRoleMenuMapper.deleteListByMenuId(menuId);
    }

    @Override
    public Set<String> getRoleMenuListByRoleId(String roleId) {
        return SysTemplatePermissionService.super.getRoleMenuListByRoleId(roleId);
    }

    @Override
    public Set<String> getRoleMenuListByRoleId(Collection<String> roleIds) {
        if (CollUtil.isEmpty(roleIds)) {
            return Collections.emptySet();
        }

        // 如果是管理员的情况下，获取全部菜单编号
        if (sysTemplateRoleService.hasAnySuperAdmin(roleIds)) {
            return convertSet(sysTemplateMenuService.getMenuList(), SysTemplateMenuDO::getSysTemplateMenuId);
        }
        // 如果是非管理员的情况下，获得拥有的菜单编号
        return convertSet(sysTemplateRoleMenuMapper.selectListByRoleId(roleIds), SysTemplateRoleMenuDO::getSysMenuId);
    }

    @Override
    public Set<String> getMenuRoleIdListByMenuIdFromCache(String menuId) {
        return convertSet(sysTemplateRoleMenuMapper.selectListByMenuId(menuId), SysTemplateRoleMenuDO::getSysRoleId);
    }


    @Override
    public String createRole(SysTemplateRoleSaveReq createReqVO) {
        return sysTemplateRoleService.createRole(createReqVO);
    }

    @Override
    public void updateRole(SysTemplateRoleUpReq updateReqVO) {
        sysTemplateRoleService.updateRole(updateReqVO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteRole(String roleId) {
        sysTemplateRoleService.deleteRole(roleId);
        // 删除相关数据
        processRoleDeleted(roleId);
    }

    @Override
    public void updateRoleStatus(String roleId, CommonStatusEnum status) {
        sysTemplateRoleService.updateRoleStatus(roleId, status);
    }

    @Override
    public void updateRoleDataScope(String roleId, SysTemplateDataScopeEnum dataScope, Set<String> dataScopeDeptIds) {
        sysTemplateRoleService.updateRoleDataScope(roleId, dataScope, dataScopeDeptIds);
    }

    @Override
    public SysTemplateRoleDO getRole(String roleId) {
        return sysTemplateRoleService.getRole(roleId);
    }

    @Override
    public SysTemplateRoleDO getRoleFromCache(String roleId) {
        return sysTemplateRoleService.getRoleFromCache(roleId);
    }

    @Override
    public List<SysTemplateRoleDO> getRoleList(Collection<String> roleIds) {
        return sysTemplateRoleService.getRoleList(roleIds);
    }

    @Override
    public List<SysTemplateRoleDO> getRoleListFromCache(Collection<String> roleIds) {
        return sysTemplateRoleService.getRoleListFromCache(roleIds);
    }

    @Override
    public List<SysTemplateRoleDO> getRoleListByStatus(Collection<CommonStatusEnum> statuses) {
        return sysTemplateRoleService.getRoleListByStatus(statuses);
    }

    @Override
    public List<SysTemplateRoleDO> getRoleList() {
        return sysTemplateRoleService.getRoleList();
    }

    @Override
    public PageResult<SysTemplateRoleDO> getRolePage(SysTemplateRolePageReq reqVO) {
        return sysTemplateRoleService.getRolePage(reqVO);
    }

    @Override
    public boolean hasAnySuperAdmin(Collection<String> roleIds) {
        return sysTemplateRoleService.hasAnySuperAdmin(roleIds);
    }

    @Override
    public void validateRoleList(Collection<String> roleIds) {
        sysTemplateRoleService.validateRoleList(roleIds);
    }

    @Override
    public String createMenu(SysTemplateMenuSaveReq createReqVO) {
        return sysTemplateMenuService.createMenu(createReqVO);
    }

    @Override
    public void updateMenu(SysTemplateMenuSaveReq updateReqVO) {
        sysTemplateMenuService.updateMenu(updateReqVO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteMenu(String menuId) {
        sysTemplateMenuService.deleteMenu(menuId);
        processMenuDeleted(menuId);
    }

    @Override
    public List<SysTemplateMenuDO> getMenuList() {
        return sysTemplateMenuService.getMenuList();
    }

    @Override
    public List<SysTemplateMenuDO> getMenuListByTenant(SysTemplateMenuListReq reqVO) {
        return sysTemplateMenuService.getMenuListByTenant(reqVO);
    }

    @Override
    public List<SysTemplateMenuDO> getMenuList(SysTemplateMenuListReq reqVO) {
        return sysTemplateMenuService.getMenuList(reqVO);
    }

    @Override
    public List<String> getMenuIdListByPermissionFromCache(String permission) {
        return sysTemplateMenuService.getMenuIdListByPermissionFromCache(permission);
    }

    @Override
    public SysTemplateMenuDO getMenu(String menuId) {
        return sysTemplateMenuService.getMenu(menuId);
    }

    @Override
    public List<SysTemplateMenuDO> getMenuList(Collection<String> menuIds) {
        return sysTemplateMenuService.getMenuList(menuIds);
    }

    @Override
    public List<SysTemplateRoleMenuResp> getRoleMenuList() {
        List<SysTemplateRoleMenuDO> sysTemplateRoleMenus = sysTemplateRoleMenuMapper.selectList();
        return SysTemplateRoleMenuConvert.INSTANCE.convert(sysTemplateRoleMenus);
    }

    /**
     * 获得自身的代理对象，解决 AOP 生效问题
     *
     * @return 自己
     */
    private SysTemplatePermissionServiceImpl getSelf() {
        return SpringUtil.getBean(getClass());
    }

}
